package emulator.shell.GUI.menu;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;

import emulator.hardware.nmos6502.Cpu6502;
import emulator.shell.GUI.graph.BitGraph;

public abstract class GraphWindow
{
	protected BitGraph panelGraph;
	protected long currentGraphRange = 1000;
	protected long currentTick = 0;
	protected Cpu6502 cpu;
	protected CpuObserver cpuObserver = new CpuObserver();

	public GraphWindow()
	{
		super();
	}

	protected JPanel createGraphFrame() {
		panelGraph = createGraph();
		JToolBar toolBar = createToolBar();
		JPanel graphFrame = new JPanel();
		graphFrame.setLayout(new BorderLayout());
		graphFrame.add(toolBar, BorderLayout.PAGE_START);
		graphFrame.add(panelGraph, BorderLayout.CENTER);
		return graphFrame;
	}

	private JToolBar createToolBar() {
		JButton buttonBack = new JButton(new ImageIcon("images/back.png"));
		buttonBack.setToolTipText("Scroll the graph back in time");
		buttonBack.addActionListener(new Back());
		JButton buttonForward = new JButton(new ImageIcon("images/forward.png"));
		buttonForward.setToolTipText("Scroll the graph forward in time");
		buttonForward.addActionListener(new Forward());
	
		JButton buttonBackPage = new JButton(new ImageIcon("images/Rewind24.gif"));
		buttonBackPage.setToolTipText("Scroll the graph back in time by one page");
		buttonBackPage.addActionListener(new PageBack());
		JButton buttonForwardPage = new JButton(new ImageIcon("images/FastForward24.gif"));
		buttonForwardPage.setToolTipText("Scroll the graph forward in time by one page");
		buttonForwardPage.addActionListener(new PageForward());
		
		JComboBox boxRange = new JComboBox(new String [] { "10", "100", "1000", "10000", "100000", "1000000", "10000000"});
		boxRange.setSelectedIndex(2);
		boxRange.addActionListener(new RangeSelect());
		
		JToolBar toolBar = new JToolBar();
		toolBar.add(buttonBackPage);
		toolBar.add(buttonBack);
		toolBar.add(boxRange);
		toolBar.add(new JLabel(" Ticks"));
		toolBar.add(buttonForward);
		toolBar.add(buttonForwardPage);
		return toolBar;
	}

	protected abstract BitGraph createGraph(); 
	protected abstract void onCpuStoppped();
	protected abstract long getMaxTicks();

	protected void updateGraphRange()
	{
		if (panelGraph != null)
		{
			if (currentTick < currentGraphRange)
				panelGraph.setRange(0, currentTick);
			else
				panelGraph.setRange(currentTick - currentGraphRange + 1, currentTick);
		}
	}

	public void moveGraph(long tickOffset)
	{
		long newEnd = currentTick + tickOffset;
		if (newEnd < currentGraphRange)
			newEnd = currentGraphRange;
		long maxTick = getMaxTicks();
		if (newEnd > maxTick)
			newEnd = maxTick;
		currentTick = newEnd;
		updateGraphRange();
		panelGraph.repaint();
	}

	public class Forward implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e)
		{
			moveGraph(panelGraph.getRange() / panelGraph.getScalesSteps());
		}

	}

	public class Back implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e)
		{
			moveGraph(-panelGraph.getRange() / panelGraph.getScalesSteps());
		}

	}
	
	public class PageForward implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e)
		{
			moveGraph(currentGraphRange);
		}

	}

	public class PageBack implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e)
		{
			moveGraph(-currentGraphRange);
		}

	}
	
	public class RangeSelect implements ActionListener 
	{
		@Override
		public void actionPerformed(ActionEvent e)
		{
			JComboBox cb = (JComboBox)e.getSource();
			String rangeText = (String)cb.getSelectedItem();
	        long newRange = Long.parseLong(rangeText);
	        long offset = newRange - currentGraphRange;
	        currentGraphRange = newRange;
	        moveGraph(offset);
		}

	}

	public class CpuObserver implements Observer, Runnable
	{
		@Override
		public void update(Observable o, Object arg)
		{
			if (!cpu.isRunning())
			{
				currentTick = getMaxTicks();
				updateGraphRange();
			    javax.swing.SwingUtilities.invokeLater(this);
			}
		}

		@Override
		public void run()
		{
			onCpuStoppped();
			if (panelGraph != null)
				panelGraph.repaint();
		}
	}
}
